/*
 Copyright 2011, 2012 Chris Banes.
 <p/>
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 <p/>
 http://www.apache.org/licenses/LICENSE-2.0
 <p/>
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
package com.example.yijian.base.third.pop.photoview;

import android.content.Context;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;

/**
 * Does a whole lot of gesture detecting.
 * 很多手势都能检测到吗
 * 自定义手势探测器类
 * Custom gesture detector class
 */
class CustomGestureDetector {

    private static final int INVALID_POINTER_ID = -1;

    private int mActivePointerId = INVALID_POINTER_ID;
    private int mActivePointerIndex = 0;
    private final ScaleGestureDetector mDetector;

    private VelocityTracker mVelocityTracker;
    private boolean mIsDragging;
    private float mLastTouchX;
    private float mLastTouchY;
    private final float mTouchSlop;
    private final float mMinimumVelocity;
    private OnGestureListener mListener;

    CustomGestureDetector(Context context, OnGestureListener listener) {
        final ViewConfiguration configuration = ViewConfiguration
                .get(context);
        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
        mTouchSlop = configuration.getScaledTouchSlop();

        mListener = listener;
        ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {

            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float scaleFactor = detector.getScaleFactor();
                if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
                    return false;
                if (scaleFactor >= 0) {
                    mListener.onScale(scaleFactor,
                            detector.getFocusX(), detector.getFocusY());
                }
                return true;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                // NO-OP
            }
        };
        mDetector = new ScaleGestureDetector(context, mScaleListener);
    }

    private float getActiveX(MotionEvent ev) {
        try {
            return ev.getX(mActivePointerIndex);
        } catch (Exception e) {
            return ev.getX();
        }
    }

    private float getActiveY(MotionEvent ev) {
        try {
            return ev.getY(mActivePointerIndex);
        } catch (Exception e) {
            return ev.getY();
        }
    }

    /**
     * Is scaling boolean.
     *  是否缩放
     * @return the boolean
     */
    public boolean isScaling() {
        return mDetector.isInProgress();
    }

    /**
     * Is dragging boolean.
     * 是否拖曳
     * @return the boolean
     */
    public boolean isDragging() {
        return mIsDragging;
    }

    /**
     * On touch event boolean.
     * 触摸事件
     * @param ev the ev
     * @return the boolean
     */
    public boolean onTouchEvent(MotionEvent ev) {
        try {
            if(ev.getPointerCount()>1)
                mDetector.onTouchEvent(ev);
            return processTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            /*
            * Fix for support lib bug, happening when onDestroy is called
            * 修正了在调用onDestroy时发生的支持库错误
            * */
            return true;
        }
    }

    private boolean processTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
            mActivePointerId = ev.getPointerId(0);

            mVelocityTracker = VelocityTracker.obtain();
            if (null != mVelocityTracker) {
                mVelocityTracker.addMovement(ev);
            }

            mLastTouchX = getActiveX(ev);
            mLastTouchY = getActiveY(ev);
            mIsDragging = false;
        } else if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) {
            final float x = getActiveX(ev);
            final float y = getActiveY(ev);
            final float dx = x - mLastTouchX, dy = y - mLastTouchY;

            if (!mIsDragging) {
                /*
                 * Use Pythagoras to see if drag length is larger than touch slop
                 * 使用毕达哥拉斯查看拖动长度是否大于触控斜率
                 * */
                mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
            }

            if (mIsDragging) {
                mListener.onDrag(dx, dy);
                mLastTouchX = x;
                mLastTouchY = y;

                if (null != mVelocityTracker) {
                    mVelocityTracker.addMovement(ev);
                }
            }
        } else if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_CANCEL) {
            mActivePointerId = INVALID_POINTER_ID;
            /*
             * Recycle Velocity Tracker
             * 回收速度跟踪
             * */
            if (null != mVelocityTracker) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
        } else if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
            mActivePointerId = INVALID_POINTER_ID;
            if (mIsDragging) {
                if (null != mVelocityTracker) {
                    mLastTouchX = getActiveX(ev);
                    mLastTouchY = getActiveY(ev);

                    /*
                     * Compute velocity within the last 1000ms
                     * 计算最后1000ms内的速度
                     * */
                    mVelocityTracker.addMovement(ev);
                    mVelocityTracker.computeCurrentVelocity(1000);

                    final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
                            .getYVelocity();

                    /*
                     *  If the velocity is greater than minVelocity, call listener
                     * 如果速度大于minVelocity，则调用listener
                     * */
                    if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
                        mListener.onFling(mLastTouchX, mLastTouchY, -vX,
                                -vY);
                    }
                }
            }

            /*
             * Recycle Velocity Tracker
             * 回收速度跟踪
             * */
            if (null != mVelocityTracker) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
        } else if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
            final int pointerIndex = Util.getPointerIndex(ev.getAction());
            final int pointerId = ev.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mActivePointerId = ev.getPointerId(newPointerIndex);
                mLastTouchX = ev.getX(newPointerIndex);
                mLastTouchY = ev.getY(newPointerIndex);
            }
        }

        mActivePointerIndex = ev
                .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
                        : 0);
        return true;
    }
}
